#pragma once

#include <AST/expr/var/VarAST.hpp>
#include <AST/expr/literal/IntAST.hpp>

class ArrayPtr : public Var {
  protected:
    using ArrayType = llvm::ArrayType;
    using InitVector = llvm::SmallVector<Expr *>;

    // 数组内元素的类型
    Type *elementType = nullptr;

    // type 是指向数组的指针

    // 数组的长度
    uint64_t length = 0;

    // 若引用数组元素，需要提供下标
    Expr *index = nullptr;

    // 列表初始化
    InitVector initVector;

    // 高维数组Expr
    ArrayPtr *hdArr = nullptr;

  public:
    // 引用一维数组
    ArrayPtr(string name, Expr *index);

    // 引用高维数组
    ArrayPtr(ArrayPtr *hdArr, Expr *index);

    // 定义一个数组，初始化为已有的数组（a=b）
    ArrayPtr(
        string name,
        bool isDefinition,
        bool isConst = true,
        Expr *initExpr = nullptr,
        bool isNullable = false,
        Type *arrayOrPtrType = nullptr);
    // Expr *lengthConstexpr = nullptr);

    // 定义一个数组，初始化为新的数组列表（a=[1,2,3]）
    ArrayPtr(
        string name,
        bool isDefinition,
        bool isConst = true,
        InitVector initVector = InitVector{},
        bool isNullable = false,
        Type *arrayOrPtrType = nullptr);
    // Type *elementType = nullptr,
    // Expr *lengthConstexpr = nullptr);

    virtual Value *codegen() override;

    virtual Value *refCodegen() override;

    virtual AllocaInst *createEntryAlloca(Function *fun);

    virtual AllocaInst *createAlloca();

    virtual AllocaInst *createEntryArrayAlloca(Function *fun);

    friend class graphviz::GraphGenerator;

    virtual VisitResult accept(ASTVisitor &visitor) const override {
        return visitor.visitArrayPtrAST(this);
    }

  protected:
    virtual Value *valCodegen() override;

    virtual Value *defCodegen() override;

    virtual Type *updateTypeByVal(const Value *val) override;

    virtual Type *updateTypeByPtr(const Value *ptr) override;
};